/*
 * Inode.cpp
 *
 *  Created on: 10 apr. 2012
 *      Author: Harm
 */

#include "Inode.h"
#include "utility/e7convert.h"

Inode::Inode(byte * d, int pos, int num) {
	inode_nr = num;
	di_mode = getshort(d, pos); /* mode and type of file (see below) */
	di_nlink = getshort(d, pos); /* number of links to file */
	di_uid = getshort(d, pos); /* owner's user id */
	di_gid = getshort(d, pos); /* inode's group id */
	di_size = getlong(d, pos); /* number of bytes in file */

	for (int i = 0; i < 13; i++) {
		di_addr[i] = getlong3(d, pos); /* disk block addresses (see below) */
	}

	pos++;
	di_atime = getlong(d, pos); /* time last accessed */
	di_mtime = getlong(d, pos); /* time last modified */
	di_ctime = getlong(d, pos); /* time created/changed */
	//cout << "\nblokken\n";
	//blokken regelen
	for (int i = 0; i < 13; i++) {
		addBlock(di_addr[i]);
		//cout << di_addr[i] << " ";
	}

	//cout << "\n";
	if (!isFull())
		return;

	//indirecte blokken 1
	if (di_addr[10] != 0) {
		cout << "size = " << di_size << " address = " << di_addr[10] << "\n";
		int indirpos1 = di_addr[10] * DBLKSIZ;
		readfirstBlocks(indirpos1, d);
	}
	if (!isFull())
		return;
	//indirecte blokken 2
	if (di_addr[11] != 0) {
		int indirpos2 = di_addr[11] * DBLKSIZ;
		readsecondBlocks(indirpos2, d);

	}
	if (!isFull())
		return;
	//indirecte blokken 3
	if (di_addr[12] != 0) {
		int indirpos3 = di_addr[12] * DBLKSIZ;
		readthirdBlocks(indirpos3, d);
	}
}

#define		X_IFMT	0170000	/* type of file (mask upper 4 bits) */
#define		X_IFIFO 0010000 /* FIFO special file */
#define		X_IFCHR	0020000	/* character special */
#define		X_IFMPC	0030000	/* multiplexed char special */
#define		X_IFDIR	0040000	/* directory */
#define		X_IFBLK	0060000	/* block special */
#define		X_IFMPB	0070000	/* multiplexed block special */
#define		X_IFREG	0100000	/* regular */

bool Inode::isDir() {
	return di_mode & X_IFDIR;
}
bool Inode::isFIFO() {
	return di_mode & X_IFIFO;
}
bool Inode::isCharSpecial() {
	return di_mode & X_IFCHR;
}
bool Inode::isCharMultiplex() {
	return di_mode & X_IFMPC;
}
bool Inode::isBlockSpecial() {
	return di_mode & X_IFBLK;
}
bool Inode::isBlockMultiplex() {
	return di_mode & X_IFMPB;
}
bool Inode::isRegular() {
	return di_mode & X_IFREG;
}

void Inode::readfirstBlocks(int blockp, byte * b) {
	cout << "\n";
	cout << "level 1  @ " << blockp << " ";
	for (int i = 0; i < 128 && isFull(); i++) {
		int n = getlong(b, blockp);

		if (n != 0) {
			cout << "[" << n << "] ";
			addBlock(n);
		}
	}
	cout << "\n";
}
void Inode::readsecondBlocks(int blockp, byte * b) {
	cout << "level 2\n";

	for (int i = 0; i < 128 && isFull(); i++) {
		int n = getlong(b, blockp);
		if (n != 0) {
			cout << "[" << n << "] ";
			readfirstBlocks((n * 512), b);
		}
	}
}

void Inode::readthirdBlocks(int blockp, byte * b) {
	cout << "level 3\n";
	for (int i = 0; i < 128 && isFull(); i++) {
		int n = getlong(b, blockp);
		if (n != 0) {
			readsecondBlocks((n * 512), b);
		}
	}
}

void Inode::print() {
	cout << inode_nr << "\n";
	cout << (int) ((di_mode)) << " ";
	cout << (int) ((di_nlink)) << " ";
	cout << (int) ((di_uid)) << " ";
	cout << (int) ((di_gid)) << " ";
	cout << (int) ((di_size)) << "\n";
	for (int i = 0; i < 13; i++)
		cout << (int) di_addr[i] << " ";
	cout << "\n";
	for (int i = 0; i < blocks.size(); i++) {
		cout << (int) blocks[i] << " ";
	}
	cout << "\n";
	cout << ctime(&di_atime) << " ";
	cout << ctime(&di_mtime) << " ";
	cout << ctime(&di_ctime) << "\n\n";
}

void Inode::dumpToFile(byte * b) {
	stringstream ss;
	ss << inode_nr << ".txt";
	fstream out(ss.str().c_str(), fstream::out);
	int q = 0;
	for (int i = 0; i < blocks.size(); i++) {
		unsigned int n = (blocks[i] * 512);
		for (unsigned int j = n; j < (n + 512); j++) {
			if (q < di_size)
				out << b[j];
		}
	}
	out.close();

}

Inode::~Inode() {
	// TODO Auto-generated destructor stub
}
